package com.xuecheng.content.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.base.constant.CourseAuditStatusConstant;
import com.xuecheng.base.constant.CourseChargeConstant;
import com.xuecheng.base.constant.CoursePublishStatusConstant;
import com.xuecheng.base.model.PageParams;
import com.xuecheng.base.model.PageResult;
import com.xuecheng.base.util.SecurityUtil;
import com.xuecheng.content.exception.*;
import com.xuecheng.content.mapper.*;
import com.xuecheng.content.model.dto.*;
import com.xuecheng.content.model.po.*;
import com.xuecheng.content.service.ICourseBaseService;
import com.xuecheng.content.service.ICoursePublishService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程基本信息 服务实现类
 * </p>
 * <p>
 * 业务层只抛出业务逻辑有关的异常，不抛出表单参数的校验异常
 * </p>
 *
 * @author 勾新杰
 * @since 2024-12-17
 */
@Service
@RequiredArgsConstructor
public class CourseBaseServiceImpl extends ServiceImpl<CourseBaseMapper, CourseBase> implements ICourseBaseService {

    private final CourseBaseMapper courseBaseMapper; // 课程基本信息Mapper

    private final CourseMarketMapper courseMarketMapper; // 课程营销信息Mapper

    private final CourseCategoryMapper courseCategoryMapper; // 课程分类Mapper

    private final TeachplanMapper teachplanMapper; // 课程计划Mapper

    private final TeachplanMediaMapper teachplanMediaMapper; // 课程媒资信息Mapper

    private final CourseTeacherMapper courseTeacherMapper; // 课程教师Mapper

    private final CourseAuditMapper courseAuditMapper; // 课程审核服务

    private ICoursePublishService coursePublishService; // 课程发布服务

    // 解决循环依赖问题，因为coursePublishService完全依赖于courseBaseService，而courseBaseService只有一个方法需要coursePublishService，所以此项延迟加载
    @Autowired
    public void setCoursePublishService(@Lazy ICoursePublishService coursePublishService) {
        this.coursePublishService = coursePublishService;
    }

    /**
     * 课程分页查询
     *
     * @param pageParams        分页参数
     * @param queryCourseParams 查询参数
     * @return 分页结果
     */
    @Override
    public PageResult<CourseBaseAuditDTO> pageQueryCourseBase(PageParams pageParams, QueryCourseParamsDTO queryCourseParams) {
        Long companyId = Long.valueOf(Objects.requireNonNull(SecurityUtil.getUser()).getCompanyId());
        // 1. 初始化分页参数
        Page<CourseBase> page = new Page<>(pageParams.getPageNo(), pageParams.getPageSize());
        // 2. 构建查询条件并分页查询
        Page<CourseBase> basePage = lambdaQuery()
                // 2.1 构建查询条件
                .like(StrUtil.isNotBlank(queryCourseParams.getCourseName()),
                        CourseBase::getName,
                        queryCourseParams.getCourseName())
                .eq(StrUtil.isNotBlank(queryCourseParams.getAuditStatus()),
                        CourseBase::getAuditStatus,
                        queryCourseParams.getAuditStatus())
                .eq(StrUtil.isNotBlank(queryCourseParams.getPublishStatus()),
                        CourseBase::getStatus,
                        queryCourseParams.getPublishStatus())
                .eq(CourseBase::getCompanyId, companyId)
                // 2.2 分页查询
                .page(page);
        List<CourseBaseAuditDTO> records = basePage.getRecords()
                .stream()
                .map(courseBase -> {
                    CourseBaseAuditDTO courseBaseAuditDTO = BeanUtil.copyProperties(courseBase, CourseBaseAuditDTO.class);
                    if (CourseAuditStatusConstant.UN_PASS.equals(courseBaseAuditDTO.getAuditStatus())) {
                        Long courseId = courseBaseAuditDTO.getId();
                        CourseAudit courseAudit = courseAuditMapper.selectLatestByCourseId(courseId);
                        if (courseAudit != null) courseBaseAuditDTO.setAuditMind(courseAudit.getAuditMind());
                    }
                    return courseBaseAuditDTO;
                }).collect(Collectors.toList());
        // 3. 封装结果并返回
        return new PageResult<>(records,
                basePage.getTotal(),
                pageParams.getPageNo(),
                pageParams.getPageSize());
    }

    /**
     * 新增课程基本信息
     *
     * @param saveCourseBaseDTO 新增课程基本信息
     * @return 新增课程基本信息
     */
    @Override
    @Transactional
    public CourseBaseInfoDTO save(SaveCourseBaseDTO saveCourseBaseDTO) {
        // 1. 新增课程基本信息
        Long courseId = saveCourseBase(saveCourseBaseDTO);
        // 2. 新增课程营销信息
        int insert = saveCourseMarket(saveCourseBaseDTO, courseId);
        if (insert <= 0) CourseFailedSaveMarketException.cast();
        // 3. 查询课程基本信息、营销信息，封装并返回
        return queryCourseBaseInfo(courseId);
    }

    /**
     * 新增课程基本信息
     *
     * @param saveCourseBaseDTO 新增课程基本信息
     * @return 新增课程基本信息
     */
    private Long saveCourseBase(SaveCourseBaseDTO saveCourseBaseDTO) {
        SecurityUtil.XcUser user = SecurityUtil.getUser();
        // 1.1 属性拷贝得到基础的课程基本信息
        CourseBase courseBase = BeanUtil.copyProperties(saveCourseBaseDTO, CourseBase.class);
        // 1.2 通过链式编程设置课程基本信息其他属性
        courseBase.setCompanyId(Long.valueOf(Objects.requireNonNull(user).getCompanyId()))
                .setCompanyName(user.getCompanyName())
                .setCreateDate(LocalDateTime.now())
                .setChangeDate(LocalDateTime.now())
                .setCreatePeople(user.getName())
                .setChangePeople(user.getName())
                .setAuditStatus(CourseAuditStatusConstant.NOT_SUBMIT)
                .setStatus(CoursePublishStatusConstant.UN_PUBLISH);
        // 1.3 插入课程基本信息
        int insert = courseBaseMapper.insert(courseBase);
        // 1.4 校验插入是否成功
        if (insert <= 0) CourseFailedSaveBaseException.cast();
        return courseBase.getId(); // 当insert插入成功后courseBase的主键会被填充
    }

    /**
     * 新增课程营销信息
     *
     * @param saveCourseBaseDTO 新增课程基本信息
     * @param courseId          课程ID
     */
    private int saveCourseMarket(SaveCourseBaseDTO saveCourseBaseDTO, Long courseId) {
        // 2.1 属性拷贝得到课程营销信息
        CourseMarket courseMarket = BeanUtil.copyProperties(saveCourseBaseDTO, CourseMarket.class);
        courseMarket.setId(courseId);
        // 2.2 校验课程营销信息的收费规则
        if (CourseChargeConstant.CHARGE.equals(courseMarket.getCharge())) {
            if (courseMarket.getPrice() == null || courseMarket.getPrice() <= 0)
                CoursePriceIllegalException.cast();
        } else courseMarket.setPrice(0.00f);
        courseMarket.setOriginalPrice(courseMarket.getPrice()); // 设置原价，只有在修改的时候会改变原价
        // 2.3 判断课程营销信息是否已存在, 如果已存在则更新，否则新增
        CourseMarket old = courseMarketMapper.selectById(courseId);
        if (old != null) return courseMarketMapper.updateById(courseMarket);
        else return courseMarketMapper.insert(courseMarket);
    }

    /**
     * 查询课程基本信息、营销信息
     *
     * @param courseId 课程ID
     * @return 课程基本信息、营销信息
     */
    private CourseBaseInfoDTO queryCourseBaseInfo(Long courseId) {
        // 3.1 查询课程基本信息
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        if (courseBase == null) return null;
        CourseBaseInfoDTO courseBaseInfoDTO = BeanUtil.copyProperties(courseBase, CourseBaseInfoDTO.class);
        // 3.2 查询课程营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        if (courseMarket == null) return null;
        BeanUtil.copyProperties(courseMarket, courseBaseInfoDTO);
        // 3.3 封装分类名称
        String mtName = courseCategoryMapper.selectById(courseBaseInfoDTO.getMt()).getName();
        String stName = courseCategoryMapper.selectById(courseBaseInfoDTO.getSt()).getName();
        courseBaseInfoDTO.setMtName(mtName);
        courseBaseInfoDTO.setStName(stName);
        // 3.4 返回
        return courseBaseInfoDTO;
    }

    /**
     * 根据课程id查询课程基本信息、营销信息
     *
     * @param id 课程id
     * @return 课程基本信息
     */
    @Override
    public CourseBaseInfoDTO getCourseBaseInfoById(Long id) {
        return queryCourseBaseInfo(id);
    }

    /**
     * 修改课程基本信息
     *
     * @param updateCourseBaseDTO 修改课程基本信息
     * @return 修改课程基本信息
     */
    @Override
    public CourseBaseInfoDTO update(UpdateCourseBaseDTO updateCourseBaseDTO) {
        // 1. 获取机构id和课程id
        SecurityUtil.XcUser user = SecurityUtil.getUser();
        Long companyId = Long.valueOf(Objects.requireNonNull(user).getCompanyId());
        Long courseId = updateCourseBaseDTO.getId();
        // 2. 根据课程id查询课程基础信息
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        // 2.1 没有课程信息
        if (courseBase == null) CourseNotFoundException.cast();
        // 2.2 该课程信息不属于当前机构
        if (!ObjectUtil.equals(companyId, courseBase.getCompanyId()))
            CourseNotBelongException.cast();
        // 3. 更新课程基本信息
        courseBase = BeanUtil.copyProperties(updateCourseBaseDTO, CourseBase.class);
        courseBase.setChangePeople(user.getName()).setChangeDate(LocalDateTime.now());
        courseBaseMapper.updateById(courseBase);
        // 4. 更新课程营销信息
        CourseMarket courseMarket = BeanUtil.copyProperties(updateCourseBaseDTO, CourseMarket.class);
        courseMarket.setId(courseId);
        courseMarketMapper.updateById(courseMarket);
        // 5. 返回修改后的课程基本信息、营销信息
        return queryCourseBaseInfo(courseId);
    }

    /**
     * 根据课程id删除课程信息
     *
     * @param id 课程id
     */
    @Override
    @Transactional
    public void deleteById(Long id) {
        CourseBase courseBase = getById(id);
        if (courseBase == null) CourseNotFoundException.cast();
        if (ObjectUtil.equals(courseBase.getAuditStatus(), CourseAuditStatusConstant.SUBMITTED))
            CourseHasBeenSubmittedException.cast();
        if (ObjectUtil.equals(courseBase.getAuditStatus(), CourseAuditStatusConstant.PASSED))
            CourseHasBeenPassedException.cast();
        if (ObjectUtil.equals(courseBase.getAuditStatus(), CourseAuditStatusConstant.UN_PASS))
            CourseHasBeenRejectedException.cast();
        courseBaseMapper.deleteById(id);
        courseMarketMapper.deleteById(id);
        teachplanMapper.deleteByCourseId(id);
        teachplanMediaMapper.deleteByCourseId(id);
        courseTeacherMapper.deleteByCourseId(id);
    }

    /**
     * 根据课程id查询课程发布信息
     *
     * @param courseId 课程id
     * @return 课程发布信息
     */
    @Override
    public CoursePreviewDTO getPublishWhole(Long courseId) {
        return coursePublishService.getCoursePublishWhole(courseId);
    }
}
